位运算

  1. 输入一个整数,输出该数二进制表示中1的个数。附加题:判断一个数是否是2的幂。
  2. 一个整数数组里除了两个数字以外,其他数字都出现两次。请找出只出现一次的数字,要求时间复杂度O(n),空间复杂度O(1)。
  3. 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/即加减乘除四则运算符号。

1、思路:

  常规方法:逐位和1做与运算,看是否为1。如果右移位,当符号位为1时,会陷入死循环(高位补1)。所以选择左移位,当标志位为0时说明所有位都移动完成。

  巧妙方法:当n-1时,与n相比,最右边的1变为0,再右侧的0变为1。所以n&(n-1)不为0,则计数加1,有几个1就有几次循环。

  判断2的幂:用二进制表示该数,如果是2的幂,则只有高位出现1,其他位都是0。

 1 int NumberOf1_Solution1(int n)
 2 {
 3     int count = 0;
 4     unsigned int flag = 1;
 5     while(flag)
 6     {
 7         if(n & flag)
 8             count ++;
 9  
10         flag = flag << 1;
11     }
12  
13     return count;
14 }
15 
16 int NumberOf1_Solution2(int n)
17 {
18     int count = 0;
19  
20     while (n)
21     {
22         ++ count;
23         n = (n - 1) & n;
24     }
25  
26     return count;
27 }

 

2、思路:

  空间复杂度O(1)说明不能用hash。真经:异或自己得0,异或0得自己。首先,所有数组中的数字都异或一遍,出现两次的相互抵消,最后的结果是两个只出现1次的数字异或的结果。其次,最右边出现1的位说明两个数在该位上不同,则以该位为0或为1分隔成两个数组。最后,在新的两个数组上都异或一遍,得两个数字。

 1 void FindNumsAppearOnce(int data[], int length, int* num1, int* num2)
 2 {
 3     if (data == NULL || length < 2)
 4         return;
 5   
 6     int resultExclusiveOR = 0;
 7     for (int i = 0; i < length; ++ i)
 8         resultExclusiveOR ^= data[i];
 9   
10     unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);    
11   
12     *num1 = *num2 = 0;
13     for (int j = 0; j < length; ++ j)
14     {
15         if(IsBit1(data[j], indexOf1))
16             *num1 ^= data[j];
17         else
18             *num2 ^= data[j];
19     }
20 }
21   
22 // 找到num从右边数起第一个是1的位
23 unsigned int FindFirstBitIs1(int num)
24 {
25     int indexBit = 0;
26     while (((num & 1) == 0) && (indexBit < 8 * sizeof(int)))
27     {
28         num = num >> 1;
29         ++ indexBit;
30     }
31   
32     return indexBit;
33 }
34  
35 // 判断数字num的第indexBit位是不是1
36 bool IsBit1(int num, unsigned int indexBit)
37 {
38     num = num >> indexBit;
39     return (num & 1);
40 }

 

3、思路:

  只能用位运算。模拟加法过程,先各个位上相加不考虑进位,再考虑进位,最后把进位加上。而0+0=0,1+1=0,0+1=1,1+0=1,即异或的结果。只有1+1=0才会产生进位,那么1&1=1,将1左移表示进位。

 1 int Add(int num1, int num2)
 2 {
 3     int sum, carry;
 4     do
 5     {
 6         sum = num1 ^ num2;
 7         carry = (num1 & num2) << 1;
 8  
 9         num1 = sum;
10         num2 = carry;
11     }
12     while(num2 != 0);
13  
14     return num1;
15 }

 

 

 

posted on 2013-03-27 11:35  月moon鸟  阅读(235)  评论(0编辑  收藏  举报

导航